package com.leon.androidui.customview;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.LinearInterpolator;

import androidx.annotation.Keep;
import androidx.annotation.Nullable;

import com.leon.androidui.R;

/**
 * 仿Flipboard动画效果
 * hencode实践
 * https://github.com/sunnyxibei/HenCoderPractice
 * https://hencoder.com/activity-mock-2/
 */
public class FlipboardView extends View {

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Bitmap bitmap;

    int rightDegreeY = 0; // 右边在Y轴方向的旋转
    int leftDegreeY = 0; // 左边在Y轴方向的旋转
    int degreeZ = 0; // 整个View在Z轴上的旋转
    ObjectAnimator animatorPartStart = ObjectAnimator.ofInt(this, "rightDegreeY", 0, 30);
    ObjectAnimator animatorPartMiddle = ObjectAnimator.ofInt(this, "degreeZ", 0, 270);
    ObjectAnimator animatorPartEnd = ObjectAnimator.ofInt(this, "leftDegreeY", 0, 30);

    AnimatorSet animatorSet = new AnimatorSet();

    Rect partFixed = new Rect();
    Rect partMove = new Rect();

    Camera camera = new Camera();
    private boolean hasDetached = false;

    public FlipboardView(Context context) {
        super(context);
        initView(context, null);
    }

    public FlipboardView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView(context, attrs);
    }

    public FlipboardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context, attrs);
    }

    private void initView(Context context, AttributeSet attrs) {
        bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.maps);

        animatorPartStart.setDuration(1500);
        animatorPartStart.setInterpolator(new LinearInterpolator());
        animatorPartStart.setStartDelay(500);

        animatorPartMiddle.setDuration(1000);
        animatorPartMiddle.setInterpolator(new AccelerateInterpolator());
        animatorPartMiddle.setStartDelay(500);

        animatorPartEnd.setDuration(1500);
        animatorPartEnd.setInterpolator(new LinearInterpolator());
        animatorPartEnd.setStartDelay(500);

        animatorSet.playSequentially(animatorPartStart, animatorPartMiddle, animatorPartEnd);

        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (hasDetached) {
                    return;
                }
                reset();
                postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        animatorSet.start();
                    }
                },500);

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
    }

    private void reset() {
        rightDegreeY = 0;
        leftDegreeY = 0;
        degreeZ = 0;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        hasDetached = false;
        animatorSet.start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        hasDetached = true;
        animatorSet.end();
    }

    public int getRightDegreeY() {
        return rightDegreeY;
    }

    @Keep
    public void setRightDegreeY(int rightDegreeY) {
        this.rightDegreeY = rightDegreeY;
        invalidate();
    }

    public int getDegreeZ() {
        return degreeZ;
    }

    @Keep
    public void setDegreeZ(int degreeZ) {
        this.degreeZ = degreeZ;
        invalidate();
    }

    public int getLeftDegreeY() {
        return leftDegreeY;
    }

    @Keep
    public void setLeftDegreeY(int leftDegreeY) {
        this.leftDegreeY = leftDegreeY;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int bitmapWidth = bitmap.getWidth();
        int bitmapHeight = bitmap.getHeight();
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;

        int x = centerX - bitmapWidth / 2;
        int y = centerY - bitmapHeight / 2;

        canvas.save();
        camera.save();
        canvas.translate(centerX, centerY);
        canvas.rotate(-degreeZ);
        partMove.set(0, -getHeight() / 2, getWidth() / 2, getHeight() / 2);
        canvas.clipRect(partMove);
        camera.rotateY(-rightDegreeY);
        camera.applyToCanvas(canvas);
        canvas.rotate(degreeZ);
        canvas.translate(-centerX, -centerY);
        camera.restore();
        canvas.drawBitmap(bitmap, x, y, paint);
        canvas.restore();

        canvas.save();
        camera.save();
        canvas.translate(centerX, centerY);
        canvas.rotate(-degreeZ);
        partFixed.set(-getWidth() / 2, -getHeight() / 2, 0, getHeight() / 2);
        canvas.clipRect(partFixed);
        camera.rotateY(leftDegreeY);
        camera.applyToCanvas(canvas);
        canvas.rotate(degreeZ);
        canvas.translate(-centerX, -centerY);
        camera.restore();
        canvas.drawBitmap(bitmap, x, y, paint);
        canvas.restore();

    }
}
